package jmcnet.libcommun.communs.newjmcnetds
{
	import flash.events.EventDispatcher;
	import flash.utils.getQualifiedClassName;
	
	import jmcnet.libcommun.communs.exceptions.ExceptionTechnique;
	import jmcnet.libcommun.logger.JMCNetLog4JLogger;
	import jmcnet.libcommun.security.BaseLoginWindow;
	import jmcnet.libcommun.security.BaseSessionManager;
	
	import mx.rpc.AbstractOperation;
	import mx.rpc.AsyncResponder;
	import mx.rpc.AsyncToken;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.remoting.RemoteObject;

	public class Methode {
		private static var log:JMCNetLog4JLogger = new JMCNetLog4JLogger(getQualifiedClassName(Methode));
		
		public var nomMethode:String;
		private var _onResultCallback:Function;
		private var _onErrorCallback:Function;
		private var _serviceOperation:AbstractOperation;
		private var _eventDispatcher:EventDispatcher=null;
		
		// Les derniers parametres pour reappel en cas de login
		private var _args:Array=null;
		
		public function Methode(nomMethode:String, onResultCallback:Function, onErrorCallback:Function, service:BlazeDSService, eventDispatcher:EventDispatcher=null) {
			log.info("Appel CTOR nomMethode="+nomMethode+" service="+service.destination);
			this.nomMethode = nomMethode;
			this._onResultCallback = onResultCallback;
			this._onErrorCallback = onErrorCallback;
			this._eventDispatcher = eventDispatcher;
			_serviceOperation = service.getOperation(nomMethode);
			if (_serviceOperation == null) {
				var msg:String="Erreur : tentative d'enregistrement de l'opération inexistante '"+nomMethode+"' sur le service '"+service.destination+"'";
				log.error(msg);
				throw ExceptionTechnique(msg);
			}
			log.info("Fin CTOR OK");
		}
		
		protected function onResult(event:mx.rpc.events.ResultEvent, token:Object=null):void {
			log.info("Appel onResult : nomMethode="+nomMethode+" event="+event+" result="+event.result);
			if (_onResultCallback != null) {
				_onResultCallback(event.result);
			}
			
			// On dispatche
			if (_eventDispatcher != null) {
				log.evt("Dispatch evt EventDelegateAppelOK type="+nomMethode);
				_eventDispatcher.dispatchEvent(new EventDelegateAppelOK(nomMethode));
			}
		}
		
		protected function onError(event:mx.rpc.events.FaultEvent, token:Object=null):void {
			log.error("Appel onError : nomMethode="+nomMethode+" event="+event+" message="+event.message);
			
			// Traitement de l'erreur
			switch (event.fault.faultCode) {
				case "Client.Authentication" :
					log.warn("Demande d'authentification");
					var loginWin:BaseLoginWindow = BaseSessionManager.sessionManager.openLoginWindow();
					
					// Pour que l'on soit rappeler lorsque le login est OK avec le resultat de l'appel du service
					if (loginWin != null) {
						loginWin.responderWhenOk = this.reAppel;
//						loginWin.responderWhenKo = this.fault;
					}
					break;
				case "Channel.Call.Failed" :
					// Si l'erreur concerne le ChannelSet, on se deloggue, avant d'appeler onTechnicalError
					log.warn("Erreur sur le ChannelSet, on se deloggue");
					BaseSessionManager.sessionManager.closeSession();
					// Il n'y a pas de break, et c'est fait exprès pour qu'on appelle onTechnicalError
					// break;
				default :
					if (_onErrorCallback != null) {
						_onErrorCallback(event.message);
					}
					
					// On dispatche
					if (_eventDispatcher != null) {
						log.evt("Dispatch evt EventDelegateAppelKO type="+nomMethode);
						_eventDispatcher.dispatchEvent(new EventDelegateAppelKO(nomMethode));
					}
					break;
			}			
		}
		
		public function appeler(args:Array):void {
			log.info("Appel appeler : nomMethode="+nomMethode+" args="+args);
			
			if (_serviceOperation == null) {
				var msg:String="Erreur : tentative d'appel de l'opération inexistante '"+nomMethode+"'";
				log.error(msg);
				throw ExceptionTechnique(msg);
			}
		
			_args = args;
			_serviceOperation.arguments = args;
			var token:AsyncToken = _serviceOperation.send();
			
			token.addResponder(new AsyncResponder(onResult, onError));
			log.info("Fin appeler : nomMethode="+nomMethode+" args="+args);
		}
		
		/**
		 * Fonction qui reeffectue l'appel précédent car une demande de login est venue s'interposée
		 */
		private function reAppel(obj:Object):void {
			appeler(_args);
		}
	}
}